/*******************************************************************************
 * Copyright (c) 2003 Boris Pruessmann and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Common Public License v0.5
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors:
 *    Boris Pruessmann - Initial implementation.
 ******************************************************************************/
package net.sourceforge.perforce.ui.internal;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import net.sourceforge.perforce.core.PerforceCorePlugin;
import net.sourceforge.perforce.core.PerforceException;
import net.sourceforge.perforce.core.api.IPerforceServer;
import net.sourceforge.perforce.core.api.IWhereResult;
import net.sourceforge.perforce.core.internal.P4TeamProvider;
import net.sourceforge.perforce.ui.PerforceUIPlugin;

import org.eclipse.core.internal.resources.ProjectDescription;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.team.core.IProjectSetSerializer;
import org.eclipse.team.core.RepositoryProvider;
import org.eclipse.ui.actions.WorkspaceModifyOperation;

/**
  * @version $Revision: 235 $
  * @author  <a href="mailto:bpruessmann@users.sourceforge.net">Boris Pruessmann</a>
  */
public class P4ProjectSetSerializer implements IProjectSetSerializer 
{
	//	------------------------------------------------------------------------------ Public Methods
	
	/** @see IProjectSetSerializer#asReference(IProject[], Object, IProgressMonitor) */
	public String[] asReference(
		IProject[] providerProjects,
		Object context,
		IProgressMonitor monitor)
		throws PerforceException 
	{
		String[] result = new String[providerProjects.length];
		for (int i = 0; i < providerProjects.length; i++)
		{
			StringBuffer buffer = new StringBuffer();
			buffer.append("1.0,");                                                     //$NON-NLS-1$
			
			IProject project = providerProjects[i];
			P4TeamProvider provider = (P4TeamProvider) RepositoryProvider.getProvider(project);
			
			IPerforceServer server = provider.getPerforceServer();
			buffer.append(server.getPort());
			buffer.append(',');
			
			IWhereResult whereResult = server.where(project);
			buffer.append(whereResult.getDepotFilename());
			buffer.append(',');
			
			buffer.append(project.getName());
			
			result[i] = buffer.toString();
		}
		
		return result;
	}

	/** @see IProjectSetSerializer#addToWorkspace(String[], String, Object, IProgressMonitor) */
	public IProject[] addToWorkspace(
		String[] referenceStrings,
		String filename,
		Object context,
		IProgressMonitor monitor)
		throws PerforceException 
	{
		final int size = referenceStrings.length;

		IPerforceServer[] servers = PerforceCorePlugin.getServerManager().getPerforceServers();
		Map serverMap = new HashMap();
		for (int i = 0; i < servers.length; i++)
		{
			IPerforceServer server = servers[i];
			if (!serverMap.containsKey(server.getPort()))
			{
				serverMap.put(server.getPort(), server);
			}
		}

		final IProject[] projects = new IProject[size];
		final IPerforceServer[] projectServers = new IPerforceServer[size];		
		final String[] projectLocation = new String[size];
		
		for (int i = 0; i < size; i++)
		{
			StringTokenizer tokenizer = new StringTokenizer(referenceStrings[i], ","); //$NON-NLS-1$
			String version = tokenizer.nextToken();
			if (!version.equals("1.0"))                                                //$NON-NLS-1$
			{
				return null;				
			}
			
			String repo = tokenizer.nextToken();
			projectServers[i] = (IPerforceServer) serverMap.get(repo);
			projectLocation[i] = tokenizer.nextToken();
			
			String projectName = tokenizer.nextToken();
			projects[i] = PerforceUIPlugin.getWorkspace().getRoot().getProject(projectName);
		}
		
		final int[] num = new int[]{ size };
		for (int i = 0; i < size; i++)
		{
			IProject project = projects[i];
			if (projectServers[i] == null || project.exists()) 
			{
				projectLocation[i] = null;
				num[0]--;
			}
		}
		
		WorkspaceModifyOperation op = new WorkspaceModifyOperation() 
		{
			public void execute(IProgressMonitor monitor) 
				throws InterruptedException, InvocationTargetException 
			{
				monitor.beginTask("", 1000 * num[0]);                                  //$NON-NLS-1$
				try 
				{
					for (int i = 0; i < size; i++) 
					{
						if (projectLocation[i] != null) 
						{							
							checkout(
								projectServers[i],
								projectLocation[i], 
								projects[i], 
								Policy.subMonitorFor(monitor, 1000));
						}
					}
				} 
				catch (PerforceException e) 
				{
					throw new InvocationTargetException(e);
				} 
				finally 
				{
					monitor.done();
				}
			}
		};

		try 
		{
			op.run(monitor);
		} 
		catch (InterruptedException e) 
		{
		} 
		catch (InvocationTargetException e) 
		{
			Throwable t = e.getTargetException();
			if (t instanceof PerforceException) 
			{
				throw (PerforceException) t;
			}
		}
		
		List result = new ArrayList();
		for (int i = 0; i < projects.length; i++) 
		{
			if (projectLocation[i] != null) 
			{
				result.add(projects[i]);
			} 
		}
		
		return (IProject[]) result.toArray(new IProject[result.size()]);
	}
	
	// ----------------------------------------------------------------------------- Private Methods

	private void checkout(
		IPerforceServer server,
		String projectLocation,
		IProject project,
		IProgressMonitor monitor) 
		throws PerforceException
	{
		IWhereResult whereResult = server.where(projectLocation);
		IPath location = new Path(whereResult.getLocalFilename());
		monitor.worked(200);
		
		IProjectDescription projectDescription = new ProjectDescription();
		projectDescription.setName(project.getName());
		projectDescription.setLocation(location);
		monitor.worked(100);
		
		try
		{		
			project.create(projectDescription, Policy.subMonitorFor(monitor, 100));

			if (!project.isOpen())
			{
				project.open(Policy.subMonitorFor(monitor, 100));
			}
			else
			{
				project.refreshLocal(IResource.DEPTH_INFINITE, Policy.subMonitorFor(monitor, 100));
			}
		}	
		catch (CoreException e)
		{
			throw new PerforceException(e.getStatus());
		}		

		PerforceCorePlugin.getServerManager().setSharing(
			project, 
			server, 
			Policy.subMonitorFor(monitor, 100));
	
		P4TeamProvider provider = 
			(P4TeamProvider) RepositoryProvider.getProvider(project);
		provider.refreshState(
			new IResource[] { project }, 
			IResource.DEPTH_INFINITE, 
			Policy.subMonitorFor(monitor, 400));
	}
}
